package com.google.code.gwt.remoteaction.server;


import java.lang.reflect.Method;
import java.util.Collection;

import net.sf.gilead.core.IPersistenceUtil;
import net.sf.gilead.core.PersistentBeanManager;
import net.sf.gilead.gwt.GwtConfigurationHelper;
import net.sf.gilead.pojo.base.ILightEntity;

import org.slf4j.Logger;

import com.google.code.gwt.remoteaction.client.Action;
import com.google.code.gwt.remoteaction.client.ActionResult;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;

@Singleton
public class ActionExecutionServiceWithGileadSupportImpl extends ActionExecutionServiceImpl{

	private static final long serialVersionUID = 1L;

	private PersistentBeanManager beanManager ;
	
	final Logger logger;

	@Inject
	  public ActionExecutionServiceWithGileadSupportImpl(@ActionExecutionLogger Logger logger,
			  Injector injector, @ActionExecutionIPersistenceUtil IPersistenceUtil iPersistenceUtil) {
		
		super(logger, injector);
		
		this.logger = logger;
		
        beanManager = GwtConfigurationHelper.initGwtStatelessBeanManager(iPersistenceUtil);

	  }
	
    @Override
	public ActionResult execute(Action action) {
		   if(beanManager == null){
			   logger.error("Cannot set PersistentBeanManager");
			   
			   ActionResultFactory resultFactory = super.getActionHandlerInstance(ActionResultFactory.class,
		                action.getClass());
			   return resultFactory.createFailureResult(new Exception("Cannot set PersistentBeanManager"));
		  
		   }
	        for (Method method : action.getClass().getMethods()) {
	        	String methodName = method.getName();
	        	if (methodName.startsWith("get") ){
	        		
	        		
	        		if(ILightEntity.class.isAssignableFrom(method.getReturnType())
	        				|| Collection.class.isAssignableFrom(method.getReturnType())){
	        			
							try {
							
							Method setterMethod = action.getClass().getMethod("set"+methodName.substring(3), method.getReturnType());
							Object mergedObject = beanManager.merge(method.invoke(action, new Object[0]));
	        				setterMethod.invoke(action, mergedObject);
							
							} catch (NoSuchMethodException e) {
								logger.error("Cannot find setter Method for "+action.getClass().getName()+".set"+methodName.substring(3)+"("+method.getReturnType().getName()+"), please implement setting method in Action Class");
							
			        		} catch (Exception e) {
			        			logger.error("Error: unable to merge input object:" + e.getMessage());
			        		}
			        		
	        		}
	        	}
	        	
	        	
	        }
	       ActionResult actionResult =  super.execute(action);
	       
	       
	       if(actionResult.getException() == null && actionResult.getResult()!=null){
	    	   
	    	   ActionResultFactory resultFactory = getActionHandlerInstance(ActionResultFactory.class,
	                action.getClass());
	    	   
	    	   try{
	    		   logger.info("Clone Object: "+actionResult.getResult().getClass().getName());
	    		   actionResult = resultFactory.createSuccessResult(beanManager.clone(actionResult.getResult(),true));
	    	   }catch(Exception e){
	    		   e.printStackTrace();
	    	   }
	    	   finally{
	    		   beanManager.getProxyStore().cleanUp();
	    	   }
	     
	       } 
	        
	       
		return actionResult;
	
	}
	
}
